
# -*- coding: utf-8-*-
import datetime
from openerp import models, api, SUPERUSER_ID
from openerp.osv import osv, fields, orm
import xlwt,StringIO,base64
import pyminizip,tempfile,os,random
SUPERUSER_ID = 1


class sale_order(osv.osv):
    _inherit = 'sale.order'

    _columns = {
        'is_card': fields.boolean(u'卡券订单'),
        'sale_order_id': fields.one2many('order.card', 'order_id', u'订单券号列表'),
        'apply_delivery_id': fields.many2one('apply.delivery', u'提货记录', copy=True)
    }

    _defaults = {
        'by_agents': lambda self, cr, uid, context: context.get('purchase_order_by_agents'),
        'is_card': lambda self, cr, uid, context: context.get('default_is_card'),
    }



class order_card(osv.osv):
    _name = 'order.card'

    def unlink(self, cr, uid, ids, context=None):
        for order_card_obj in self.browse(cr, uid, ids, context=context):
            if order_card_obj.is_shipped:  # 判断卡券是否已发货
                raise osv.except_osv(u'错误', u'%s订单已发货')
            # 循环得出订单明细表里存在的对外编号列表
            for code in self.pool['product.card.issue'].get_exist_codes(cr, uid, order_card_obj.product_id.id,
                                                                        order_card_obj.starting_number.code,
                                                                        order_card_obj.continue_number,
                                                                        context=context):
                # 通过对外编号找出卡券(card_id),并释放锁定
                card_id = self.pool["product.card.line"].search(
                    cr, uid, [('code', '=', code)])
                card_obj = self.pool["product.card.line"].browse(
                    cr, uid, card_id, context=context)
                card_obj.write({'delivery_lock': False})
        return super(order_card, self).unlink(cr, uid, ids, context=context)

    def create(self, cr, uid, vals, context=None):
        card = self.pool["product.card.line"].browse(
            cr, uid, vals.get('starting_number'), context=context)
        # 统计和判断 输入的 要出入库的 产品和出入库单的 产品的数量 是否一致
        if vals.get('default_picking_id'):
            picking_product_num,order_card_num=0,0
            for move in self.pool.get('stock.move').search(cr, uid,[('picking)id', '=', vals.get('picking_id'))
                                                                    ,('product_id','=',card[0].product_id.id)],
                                                           context=context):
                picking_product_num+=move.product_uom_qty
            for order_card_obj in self.search(cr.uid,[('picking)id', '=', vals.get('picking_id'))
                                                                    ,('product_id','=',card[0].product_id.id)],context):
                order_card_num+=order_card_obj.continue_number
            if picking_product_num< order_card_num+vals.get('continue_number'):
                raise osv.except_osv(u'错误', u'您要出（入）库的卡券的数量，大于出（入）库单的产品的数量!')
        continue_number = vals.get("continue_number", 1)

        #　判断本次输入的产品和　出入库单的产品是否一致
        picking_obj = self.pool.get('stock.picking').browse(cr,uid,vals.get('picking_id'),context=context)
        product_id_list = []
        for move in picking_obj.move_lines:
            product_id_list.append(move.product_id.id)
        if card and card[0].product_id.id not in product_id_list:
            raise osv.except_osv(u'错误', u'您创建的卡券订单行的产品和出入库单的产品不相同!')
        # 卡券的状态，是否已被锁定，是否已被　发货，是否已被兑换！
        for code in self.pool['product.card.issue'].get_exist_codes(cr, uid, card.product_id.id,
            card.code,continue_number, context=context):
            card_id = self.pool["product.card.line"].search(cr, uid, [('code', '=', code)])
            card_obj = self.pool["product.card.line"].browse(
                cr, uid, card_id, context=context)
            if vals.get('po_id') and card_obj.is_enabled:
                raise osv.except_osv(u'错误', u'卡券%s已经入库（启用），请核对后再进行操作'%(code))
            if vals.get('order_id') and not card_obj.is_enabled:
                raise osv.except_osv(u'错误', u'输入的卡券号码%s没有入库（启用），请核对后再进行操作！'%(code))
            if vals.get('order_id') and  card_obj.is_active:
                raise osv.except_osv(u'错误', u'输入的卡券号码%s已经出库（激活），请核对后在进行操作！' % (code))
            if card_obj.is_exchanged == True:
                raise osv.except_osv(u'错误', u'券号%s已被兑换' % code)
            if card_obj.delivery_lock:
                order_card_id = self.search(
                    cr, uid, [('ending_number', '>=', card_obj.code), ('starting_number_copy', '<=', card_obj.code)],
                    context=context)
                order_card_obj = self.browse(
                    cr, uid, order_card_id, context=context)
                raise osv.except_osv(u'错误', u'券号%s已经被发货单%s锁定' % (
                    code, order_card_obj.picking_id.name))
            card_obj.write({'delivery_lock': True})
        return super(order_card, self).create(cr, uid, vals, context=context)

    # onchange方法，判断起始券号连续可用数量是否足够
    def onchange_end_number(self, cr, uid, ids, starting_number, continue_number, context=None):
        if starting_number and continue_number:
            card_line_obj = self.pool.get('product.card.line').browse(
                cr, uid, starting_number, context=context)
            # 获得卡券明细中该卡券的列表
            code = self.pool.get("product.card.issue").get_exist_codes(
                cr, uid, card_line_obj.product_id.id, card_line_obj.code, continue_number, context=context)
            if len(code) == continue_number:
                return {'value': {'continue_number': continue_number}}
            else:
                return {'warning': {'title': u'警告', 'message': u'此起始券号连续可用数量不足'}, 'value': {'continue_number': 1}}

    # 在加载页面时动态的对start_number进行domain过滤。出库时必须是属于自己的，入库时，卡券的归属方必须是不属于自己的
    # 获取结束券号
    def end_number(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            card_line_obj = self.pool.get('product.card.line').browse(
                cr, uid, line.starting_number.id, context=context)
            # 获得卡券明细中该卡券的列表
            res[line.id] = self.pool.get("product.card.issue").get_next_n_number(
                card_line_obj.code, line.continue_number - 1)
        return res

    _columns = {
        'order_id': fields.many2one('sale.order', u'订单号', domain=[('state', 'not in', ['draft', 'done'])]),
        'picking_id': fields.many2one('stock.picking', u'发货单号'),
        'starting_number': fields.many2one('product.card.line', u'起始号码',
                                           domain=[('delivery_lock', '=', False), ('is_enabled', '=', True)],
                                           required=True),
        'starting_number_copy': fields.related('starting_number', 'code', type="char", string=u'起始号码',
                                               readonly='1', store=True),
        'product_id': fields.related('starting_number', 'product_id', type='many2one', relation='product.product',
                                     string=u'产品名称',  readonly='1', store=True),
        # 标识该记录是否在卡券激活或者取消激活时创建
        'is_active': fields.boolean(u'是否激活'),
        'continue_number': fields.integer(u'卡券数量', required=True),
        'ending_number': fields.function(end_number, type='char', string=u'结束券号', store=True),
        'is_shipped': fields.boolean(u'是否发货'),
        'amount': fields.float(u'金额', digits=(16, 2)),
        'partner_id': fields.related('picking_id', 'partner_id', type='many2one', relation='res.partner', string=u'客户',
                                      readonly=True, store=True),
        'shipped_date': fields.date(u'发货日期'),
        'picking_type_code': fields.char(string=u'出库单类型'),
        'po_id': fields.many2one('purchase.order', string=u'采购单'),
    }
    def _set_product_id(self,cr,uid,context=None):
        pick_obj = self.pool.get('stock.picking').browse(cr, uid, context.get('active_id'),context=context)
        product_ids=[]
        if pick_obj:
            for line in pick_obj.move_lines:
                product_ids.append(line.product_id.id)
        return product_ids and  product_ids[0] or False

    def _get_picking_type_code(self,cr,uid,context=None):
        pick_obj = self.pool.get('stock.picking').browse(cr, uid, context.get('default_picking_id'), context=context)
        if pick_obj:
            return pick_obj.picking_type_code or False
        else:
            return False

    def _get_picking_po_id(self,cr,uid,context=None):
        pick_obj = self.pool.get('stock.picking').browse(cr, uid, context.get('default_picking_id'), context=context)
        if pick_obj.po_id:
            return pick_obj.po_id.id or False
        else:
            return False

    def _get_picking_order_id(self,cr,uid,context=None):
        pick_obj = self.pool.get('stock.picking').browse(cr, uid, context.get('default_picking_id'), context=context)
        if pick_obj.so_id:
            return pick_obj.so_id.id or False
        else:
            return False

    _defaults = {
        'picking_type_code':_get_picking_type_code,
        'continue_number': 1,
        'po_id':_get_picking_po_id,
        'order_id':_get_picking_order_id,
    }


class purchase_order_line(osv.osv):
    _inherit = 'purchase.order.line'
    _columns = {
        'create_card_num': fields.integer(u'待生成卡券数量'),
    }

    def create(self, cr, uid, vals, context=None):
        po_id=super(purchase_order_line, self).create(cr, uid, vals, context=context)
        for po_line in self.browse(cr, uid, po_id, context=context):
            if po_line.product_id.is_card:
                po_line.write({'create_card_num': vals.get('product_qty')})
        return po_id

    def write(self, cr, uid, ids, vals, context=None):
        for po_line in self.browse(cr, uid, ids, context=context):
            if vals.get('product_qty') and po_line.product_id.is_card:
                create_card_num = po_line.product_qty - po_line.create_card_num
                if create_card_num > vals.get('product_qty'):
                    raise osv.except_osv(u'错误', u'采购订单数量不允许小于，已发行卡券的数量！')

                vals.update({'create_card_num': vals.get('product_qty') - create_card_num})
        return super(purchase_order_line, self).write(cr, uid, ids, vals, context=context)

    def create_card_password(self, cr, uid, ids, context=None):
        po_obj = self.browse(cr, uid, ids, context=context)
        product_ids = []
        for line in po_obj:
            product_ids.append((line.product_id.id, line.create_card_num))
        if len(product_ids) > 1 or len(product_ids) == 0:
            raise osv.except_osv(u'错误', u'一个卡券采购单智能处理一采购单行!')
        model_data_obj = self.pool.get('ir.model.data')
        product_card_produce_form_id = model_data_obj.xmlid_to_res_id(
            cr, SUPERUSER_ID, 'dftg_product_card.product_card_produce_form')
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'product.card.issue',
            'view_mode': 'form',
            'view_type': 'tree,form',
            'name': u'生成卡券密码',
            'target': 'new',
            'views': [(product_card_produce_form_id, 'form')],
            'context': "{'default_product_id':%s,'default_operation_type':'issue','default_po_id':%s,\
                      'default_quantity':%s,'default_po_line_id':%s}" % (product_ids[0][0], po_obj.order_id.id,product_ids[0][1], ids[0]),
        }

class purchase_order(osv.osv):
    _inherit = 'purchase.order'

    _columns = {
        'is_card': fields.boolean(u'卡券订单'),
        'po_card_ids': fields.one2many('order.card', 'po_id', u'订单券号列表'),
    }



class sale_order_line(osv.osv):
    _inherit = 'sale.order.line'
    _columns = {
        'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('sale_ok', '=', True)],
                                      change_default=True, readonly=True, states={'draft': [('readonly', False)]},
                                      ondelete='restrict'),
        'floor_price': fields.float(string=u'最低售价'),
    }
    # 订单产品更改时，若是卡券产品更新单价，并把产品单价存入最低售价字段


class stock_picking(osv.osv):
    _inherit = 'stock.picking'

    # 判断是否是卡券移库单
    def get_is_card(self, cr, uid, ids, name, args, context=None):
        res = {}
        for picking in self.browse(cr, uid, ids, context=context):
           if picking.so_id:
               res[picking.id]=picking.so_id.is_card
           elif picking.po_id:
               res[picking.id] = picking.po_id.is_card
        return res

    _columns = {
        'order_card_id': fields.one2many("order.card", 'picking_id', u'订单券号列表'),
        'po_id':fields.many2one('purchase.order',u'采购单'),
        'so_id': fields.many2one('sale.order', u'销售订单'),
        'is_card': fields.function(get_is_card, type='boolean', string='是否是卡券移库单', store=True),
    }


class stock_transfer_details(osv.TransientModel):
    _inherit = 'stock.transfer_details'

    @api.one
    def do_detailed_transfer(self):
        '''  卡券产品发货时更新卡券信息  '''
        res = {}  # 查出要出库的产品的列表和数量，核对卡券中订单券号列表中的订单的卡券数量，如果不对应则，报错。
        if self.picking_id.is_card and not self.picking_id.origin_picking_id:
            ''' 按产品汇总数量'''
            for item in self.item_ids:
                if item.product_id.is_card:
                    if res.has_key(item.product_id.id):
                        res[item.product_id.id] += item.quantity
                    else:
                        res.update({item.product_id.id: item.quantity})
            if not self.picking_id.order_card_id:
                self.check_split_shipment(res, self.picking_id)
            # 查出order_card中的订单的产品的数量，并根据产品id和产品的数量核对，
            if self.picking_id.picking_type_code == "outgoing":
                flag = 1
            elif self.picking_id.picking_type_code == "incoming":
                flag = 0
            self.picking_card_operation(res, flag)
        return super(stock_transfer_details, self).do_detailed_transfer()

    def check_split_shipment(self, item_products, picking_row):
        create_vals = {}
        order_line_dict = {}
        if picking_row.so_id:
            order_line_dict = {}
            for line in picking_row.so_id.order_line:
                if line.product_id.is_card:
                    order_line_dict.update({line.product_id.id: int(line.product_uom_qty)})
            create_vals = {'order_id': picking_row.so_id.id}
        elif picking_row.po_id:
            order_line_dict = {}
            for line in picking_row.po_id.order_line:
                if line.product_id.is_card:
                    order_line_dict.update({line.product_id.id: int(line.product_qty)})
            create_vals = {'po_id': picking_row.po_id.id}
        for product_id, qty in order_line_dict.iteritems():
            if item_products.get(product_id, False) and item_products.get(product_id) == qty:
                card_line_rows = self.env['product.card.line'].search([('product_id', '=', product_id)],
                                                                      order='code')
                if len(card_line_rows) == qty:
                    create_vals.update({
                        'continue_number': qty,
                        'picking_id': picking_row.id,
                        'starting_number': card_line_rows[0].id,
                        'product_id': product_id,
                        'is_shipped': False,
                        'picking_type_code': picking_row.picking_type_code,
                        'ending_number': card_line_rows[qty - 1].id,
                    })
                    self.env['order.card'].create(create_vals)
        return True
 
    def picking_card_operation(self, res, flag):
        card_ids = []
        card_ids_all = []
        all_codes = []
        product_issue_obj_old = self.pool['product.card.issue']
        product_track_obj_new = self.env['product.card.track']
        product_line_obj_new = self.env['product.card.line']
        for key in res.keys():
            all_number = 0
            # order_line=self.env['sale.order.line'].search([('product_id','=',key)])[0]
            # 循环得出order_card中，卡券产品在待出库的销售订单中存在且未发货的列表
            for order_card in self.env['order.card'].search(
                    ['&', '&', ('picking_id', '=', self.picking_id.id),
                     ('starting_number.product_id', '=', key), ('is_shipped', '=', False)]):
                # 统计数量并把发货状态及时间存入order_card表
                all_number += order_card.continue_number
                order_card.sudo().write(
                    {'is_shipped': True, 'shipped_date': datetime.datetime.now()})  # 在order_card表中标记已发货
                codes = product_issue_obj_old.get_exist_codes(
                    self._cr, self._uid, order_card.product_id.id, order_card.starting_number.code,
                    order_card.continue_number, context=self._context)
                card_lines = product_line_obj_new.search(
                    [('code', 'in', codes)])
                all_codes.extend(codes)
                for card_line in card_lines:
                    # 判断卡券明细列表中是否存在卡券发行列表行，并释放订单发货锁定
                    if not card_line:
                        raise osv.except_osv(
                            u'警告！', u'%s不存在卡券' % card_line.code)
                    # 如果是出库订单
                    if flag == 1:
                        # 在日志表(track)中增加一条记录，表明产品owner的归属变更,记录operation_type
                        product_track_obj_new.create({'card_line_id': card_line.id, 'code': card_line.code,
                                                      'operation_type': 'active',
                                                      'changed_field': u'是否激活',
                                                      'old_value': '激活',
                                                      'new_value': '启用',
                                                      })
                        card_ids.append(card_line.id)
                    # 如果是入库订单
                    else:
                        card_ids_all.append(card_line.id)
                        # 增加一条日志表（track）记录, 更新owner并记录operation_type
                        product_track_obj_new.create({'card_line_id': card_line.id, 'code': card_line.code,
                                                      'operation_type': 'enable',
                                                      'changed_field': u'是否启用',
                                                      'old_value': '禁用',
                                                      'new_value': '启用',
                                                      })
                continue
            # 如果是出库单
            if res[key] != all_number:
                if flag == 1:
                    raise osv.except_osv(
                        u'错误', u'出库数量与订单券号列表中的量不符,\n 请返回到出库单上点击【输入券号】按钮')
                else:
                    raise osv.except_osv(
                        u'错误', u'入库库数量与订单券号列表中的量不符，\n 请返回到出库单上点击【输入券号】按钮')
        all_card_lines = product_line_obj_new.search(
            [('id', 'in', card_ids)])
        all_card_incoming = product_line_obj_new.search(
            [('id', 'in', card_ids_all)])
        if flag == 1:
            all_card_lines.write({'is_active': True, 'delivery_lock': False,'so_id':self.picking_id.so_id.id})
        else:
            all_card_incoming.write({'is_enabled': True, 'delivery_lock': False})


class code_password_export_wizard(osv.osv):
    _name = 'code.password.export.wizard'

    def send_password_to_user(self,cr,uid,password,user_id,context =None):

        return True

    def get_purchase_order_card_password(self, cr, uid, ids, context=None):
        card_password_obj = self.pool.get('product.card.password')
        if context is None:
            context = {}
        if isinstance(ids, int):
            this_id = ids
        else:
            this_id = ids[0]
        xls = StringIO.StringIO()
        xls_workbook = xlwt.Workbook(encoding="utf8")
        data_sheet = xls_workbook.add_sheet('data')
        card_line = self.pool.get('product.card.line').search(cr, uid, [('po_id', '=', context.get('active_id'))],
                                                              context=context)
        po_obj = self.pool.get('purchase.order').browse(cr,uid, context.get('active_id'),context=context)
        if not card_line:
            raise osv.except_osv(
                u'错误', u'还没有生成券号密码!')
        selected = card_password_obj.search(cr, SUPERUSER_ID, [('line_id', 'in', card_line)], context=context)
        field_names = ['line_id', 'password']
        header = [u"卡券号码", u"密码"]
        length = len(header)
        for i in range(length):
            data_sheet.write(0, i, header[i])
        export_data = card_password_obj.export_data(
            cr, SUPERUSER_ID, selected, [field_names[name] for name in xrange(length)], context=context).get('datas', [])
        row = 1
        for record in export_data:
            for i in range(len(record)):
                if record[i]:
                    export_value = str(record[i])  # 将数字转成字符串，以免被excel变成科学计数法
                    data_sheet.write(row, i, export_value)
            row += 1
        xls_workbook.save(xls)
        xls.seek(0)
        password_card = tempfile.gettempdir()
        xls_workbook.save(password_card+'/password.xls')
        mkstemp,password_card_zip = tempfile.mkstemp()
        password = random.sample(list(range(10)), 8)
        password_str =''.join(map(str,password))
        password_tip_message = "采购单%s 的卡券产品券号密码文件解压密码:%s\n 如不是本人操作请尽快联系管理员!" %(po_obj.name,password_str)
        self.send_password_to_user(cr, uid, password_tip_message,po_obj.create_uid.id, context=context)
        pyminizip.compress(password_card+'/password.xls',password_card_zip, password_str,6)
        f = open(password_card_zip, 'r')
        out = base64.encodestring(f.read())
        f.close()
        os.unlink(password_card+'/password.xls')
        os.unlink(password_card_zip)
        vals = {'data': out,
                'filename': u'%s券号密码.zip' %po_obj.name,
                'state': '2',
                }
        self.write(cr, uid, ids, vals, context=context)
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'code.password.export.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'res_id': this_id,
            'views': [(False, 'form')],
            'context': "{'code_password':'True'}",
            'target': 'new',
        }


    _columns = {
        'exported': fields.integer(u'之前已导出', readonly=1),
        'filename': fields.char(u'文件名', readonly=1),
        'data': fields.binary(u'券号密码文件', readonly=1),
        'state': fields.boolean(string='状态')
    }
    _default = {
        'filename': u'要导出的券号密码列表',
        'state': False,
    }
